﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using XukaShop.Common;
using XukaShop.Models.ConcertModel;
using XukaShop.Models.Entities;

namespace XukaShop.Dao
{
    public class ProductDao
    {
        private FashionShopEntities _db = new FashionShopEntities();

        /// <summary>
        /// Get all products in DB
        /// </summary>
        /// <returns></returns>
        public List<ProductConcert> GetAllProduct()
        {
            var selectProducts = (from product in _db.Product
                                  where product.IsDelete == false
                                  select product).ToList().OrderBy(model => model.DateInput);

            List<ProductConcert> lstProductEnt = new List<ProductConcert>();
            foreach (var product in selectProducts)
            {
                ProductConcert productEnt = new ProductConcert();
                productEnt.Product = product;
                productEnt.GenderValue = this.GetGenderValue(product.GenderId);
                productEnt.ProductTypeValue = CommonFunc.GetProductTypeValue(product.ProductTypeId);
                if (product.PromotionId.HasValue)
                {
                    productEnt.DiscountValue = product.Promotion.Discount;
                }
                lstProductEnt.Add(productEnt);
            }
            return lstProductEnt;
        }

        /// <summary>
        /// Get a product by productId
        /// </summary>
        /// <param name="productCode"></param>
        /// <returns></returns>
        public ProductConcert GetProductByCode(string productCode)
        {
            var selectProduct = (from product in _db.Product
                                 where product.ProductCode == productCode
                                 select product).FirstOrDefault();
            ProductConcert productEnt = new ProductConcert();
            productEnt.Product = selectProduct;
            productEnt.GenderValue = this.GetGenderValue(selectProduct.GenderId);
            productEnt.ProductTypeValue = CommonFunc.GetProductTypeValue(selectProduct.ProductTypeId);
            if (selectProduct.PromotionId.HasValue)
            {
                productEnt.DiscountValue = selectProduct.Promotion.Discount;
            }
            var selectProductLocation = (from productLocation in _db.ProductLocation
                                         where productLocation.ProductCode == productCode
                                               && productLocation.IsDelete == false
                                         select productLocation).ToList();
            var lstLocationId = string.Empty;
            foreach (var location in selectProductLocation)
            {
                if (selectProductLocation.IndexOf(location) != selectProductLocation.Count - 1)
                {
                    lstLocationId = lstLocationId + location.LocationId + ",";
                }
                else
                {
                    lstLocationId = lstLocationId + location.LocationId;
                }
            }
            productEnt.ListLocationId = lstLocationId;
            return productEnt;
        }

        /// <summary>
        /// Get Product information by Name
        /// </summary>
        /// <param name="productName"></param>
        /// <returns></returns>
        public ProductConcert GetProductByName(string productName)
        {
            var selectProduct = (from product in _db.Product
                                 where product.ProductName == productName
                                 select product).FirstOrDefault();
            ProductConcert productEnt = new ProductConcert();
            productEnt.Product = selectProduct;
            productEnt.GenderValue = this.GetGenderValue(selectProduct.GenderId);
            productEnt.ProductTypeValue = CommonFunc.GetProductTypeValue(selectProduct.ProductTypeId);
            if (selectProduct.PromotionId.HasValue)
            {
                productEnt.DiscountValue = selectProduct.Promotion.Discount;
            }
            return productEnt;
        }

        /// <summary>
        /// Get list products are new
        /// </summary>
        /// <returns></returns>
        public List<ProductConcert> GetListNewProduct()
        {
            var selectProducts = (from product in _db.Product
                                  where product.ProductTypeId == CommonConst.PRODUCT_TYPE_NEW
                                  && product.IsDelete == false
                                  select product).ToList();
            List<ProductConcert> lstProductEnt = new List<ProductConcert>();
            foreach (var product in selectProducts)
            {
                ProductConcert productEnt = new ProductConcert();
                productEnt.Product = product;
                productEnt.GenderValue = this.GetGenderValue(product.GenderId);
                productEnt.ProductTypeValue = CommonFunc.GetProductTypeValue(product.ProductTypeId);
                if (product.PromotionId.HasValue)
                {
                    productEnt.DiscountValue = product.Promotion.Discount;
                }
                lstProductEnt.Add(productEnt);
            }
            return lstProductEnt;
        }

        /// <summary>
        /// Get list products are comming soon
        /// </summary>
        /// <returns></returns>
        public List<ProductConcert> GetListCommingSoonProduct()
        {
            var selectProducts = (from product in _db.Product
                                  where product.ProductTypeId == CommonConst.PRODUCT_TYPE_COMMING_SOON
                                  && product.IsDelete == false
                                  select product).ToList();
            List<ProductConcert> lstProductEnt = new List<ProductConcert>();
            foreach (var product in selectProducts)
            {
                ProductConcert productEnt = new ProductConcert();
                productEnt.Product = product;
                productEnt.GenderValue = this.GetGenderValue(product.GenderId);
                productEnt.ProductTypeValue = CommonFunc.GetProductTypeValue(product.ProductTypeId);
                if (product.PromotionId.HasValue)
                {
                    productEnt.DiscountValue = product.Promotion.Discount;
                }
                lstProductEnt.Add(productEnt);
            }
            return lstProductEnt;
        }

        /// <summary>
        /// Get list Product Size by product code
        /// </summary>
        /// <param name="productCode"></param>
        /// <returns></returns>
        public List<ProductSize> GetListProductSize(string productCode)
        {
            var selectProductSize = (from productSize in _db.ProductSize
                                     where productSize.ProductCode == productCode
                                     select productSize).ToList();
            return selectProductSize;
        }

        /// <summary>
        /// Get Product Size by ProductSizeId
        /// </summary>
        /// <param name="productSizeId"></param>
        /// <returns></returns>
        public ProductSize GetProductSizeById(int productSizeId)
        {
            var selectProductSize = (from productSize in _db.ProductSize
                                     where productSize.Id == productSizeId
                                     select productSize).FirstOrDefault();
            return selectProductSize;
        }

        /// <summary>
        /// Get Product Location by Id
        /// </summary>
        /// <param name="productLocationId"></param>
        /// <returns></returns>
        public ProductLocation GetProductLocationById(int productLocationId)
        {
            var selectProductLocation = (from productLocation in _db.ProductLocation
                                         where productLocation.Id == productLocationId
                                         select productLocation).FirstOrDefault();
            return selectProductLocation;
        }

        /// <summary>
        /// Get list product's image by product code
        /// </summary>
        /// <param name="productCode"></param>
        /// <returns></returns>
        public List<ProductImageConcert> GetListProductImageConcertByCode(string productCode)
        {
            List<ProductImageConcert> lstProductImage = new List<ProductImageConcert>();
            var selectProductImage = (from productImage in _db.ProductImage
                                      where productImage.ProductCode == productCode
                                      select productImage).ToList();
            foreach (var productImage in selectProductImage)
            {
                ProductImageConcert image = new ProductImageConcert();
                // Get name for image
                image.ImageName = productImage.Image;

                // Get Image Path
                if (productImage.Image.Contains(CommonConst.FEMALE_PREFIX))
                {
                    image.ImagePath = CommonConst.FEMALE_PREFIX + "/" + productImage.Image;
                }
                else
                {
                    image.ImagePath = CommonConst.MALE_PREFIX + "/" + productImage.Image;
                }

                // If last item, don't need [,] character
                if (selectProductImage.IndexOf(productImage) == selectProductImage.Count - 1)
                {
                    image.IsFinalItem = true;
                }
                else
                {
                    image.IsFinalItem = false;
                }

                // Get Product Image Information
                image.ProductImageInfor = "[" + productImage.Image + "/" + productImage.Image + "]";

                lstProductImage.Add(image);
            }
            return lstProductImage;
        }

        /// <summary>
        /// Get list product's image basic information
        /// </summary>
        /// <param name="productCode"></param>
        /// <returns></returns>
        public List<ProductImage> GetListProductImageByCode(string productCode)
        {
            List<ProductImageConcert> lstProductImage = new List<ProductImageConcert>();
            var selectProductImage = (from productImage in _db.ProductImage
                                      where productImage.ProductCode == productCode
                                      select productImage).ToList();
            return selectProductImage;
        }

        /// <summary>
        /// Get list product location
        /// </summary>
        /// <param name="productCode"></param>
        /// <returns></returns>
        public List<ProductLocation> GetListProductLocationByCode(string productCode)
        {
            List<ProductLocation> lstProductLocation = new List<ProductLocation>();
            lstProductLocation = (from productLocation in _db.ProductLocation
                                  where productLocation.ProductCode == productCode
                                  select productLocation).ToList();
            return lstProductLocation;
        }

        /// <summary>
        /// Create new product
        /// </summary>
        /// <param name="productEnt"></param>
        /// <returns></returns>
        public bool CreateProduct(Product productEnt)
        {
            try
            {
                _db.Product.Add(productEnt);
                var queryResult = _db.SaveChanges();
                if (queryResult > 0)
                {
                    return true;
                }
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Edit a Product
        /// </summary>
        /// <param name="brandModel"></param>
        /// <returns></returns>
        public bool EditProduct(Product productEnt)
        {
            try
            {
                _db.Product.Attach(productEnt);
                _db.Entry(productEnt).State = EntityState.Modified;
                var queryResult = _db.SaveChanges();
                if (queryResult > 0)
                {
                    return true;
                }
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Delete a Product
        /// </summary>
        /// <param name="brandId"></param>
        /// <returns>Id of brand</returns>
        public bool DeleteProduct(string productCode)
        {
            try
            {
                Product productEnt = new Product();
                productEnt = (from product in _db.Product
                              where product.ProductCode == productCode
                              select product).FirstOrDefault();
                if (productEnt != null)
                {
                    productEnt.IsDelete = true;
                    _db.Product.Attach(productEnt);
                    _db.Entry(productEnt).State = EntityState.Modified;
                    var queryResult = _db.SaveChanges();
                    if (queryResult > 0)
                    {
                        return true;
                    }
                    return false;
                }
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Delete all product image in Databased
        /// </summary>
        /// <param name="productCode"></param>
        /// <returns></returns>
        public bool DeleteAllProductImage(string productCode)
        {
            try
            {
                List<ProductImage> lstProductImage = new List<ProductImage>();
                lstProductImage = (from productImage in _db.ProductImage
                                   where productImage.ProductCode == productCode
                                   select productImage).ToList();
                foreach (var item in lstProductImage)
                {
                    _db.ProductImage.Remove(item);
                }
                var resultQuery = _db.SaveChanges();
                if (resultQuery > 0)
                {
                    return true;
                }
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Save Product Size
        /// </summary>
        /// <param name="lstProductSizeId"></param>
        /// <param name="productCode"></param>
        /// <returns></returns>
        public bool SaveProductSize(List<string> lstProductSizeId, string productCode)
        {
            try
            {
                List<ProductSize> lstOldProductSize = new List<ProductSize>();
                lstOldProductSize = this.GetListProductSize(productCode);
                Dictionary<int, bool> dicDetechProductSize = new Dictionary<int, bool>();
                foreach (var item in lstOldProductSize)
                {
                    dicDetechProductSize.Add(item.Id, false);
                }

                // Loop in List sizeId, if don't have any record which has the same sizeId and productCode => create it, else update it
                foreach (var sizeId in lstProductSizeId)
                {
                    var sizeIdValue = Convert.ToInt32(sizeId);
                    var isExisted = _db.ProductSize.Any(model => model.SizeId == sizeIdValue && model.ProductCode == productCode);
                    if (!isExisted)
                    {
                        ProductSize productSize = new ProductSize();
                        productSize.ProductCode = productCode;
                        productSize.SizeId = Convert.ToInt32(sizeId);
                        _db.ProductSize.Add(productSize);
                    }
                    else
                    {
                        var selectProductSize = (from productSize in _db.ProductSize
                                                 where productSize.SizeId == sizeIdValue && productSize.ProductCode == productCode
                                                 select productSize).FirstOrDefault();

                        // If is existed in Product Size and when update, this ProductSizeId still keep to use, set flag is true                
                        if (dicDetechProductSize.ContainsKey(selectProductSize.Id))
                        {
                            dicDetechProductSize[selectProductSize.Id] = true;
                        }
                    }
                }

                // Loop in Dictionary, if item has flag is false, that means this item don't keep to use, so delete it
                foreach (var item in dicDetechProductSize)
                {
                    if (item.Value == false)
                    {
                        ProductSize productSizeEnt = new ProductSize();
                        productSizeEnt = this.GetProductSizeById(item.Key);

                        if (productSizeEnt != null)
                        {
                            _db.ProductSize.Remove(productSizeEnt);
                        }
                        else
                        {
                            return false;
                        }
                    }
                }
                var resultQuery = _db.SaveChanges();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Update Product Size
        /// </summary>
        /// <param name="productSizeEnt"></param>
        /// <returns></returns>
        public bool UpdateProductSize(ProductSize productSizeEnt)
        {
            try
            {
                _db.ProductSize.Attach(productSizeEnt);
                _db.Entry(productSizeEnt).State = EntityState.Modified;
                var queryResult = _db.SaveChanges();
                if (queryResult > 0)
                {
                    return true;
                }
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Save an image of a product
        /// </summary>
        /// <param name="productImage"></param>
        /// <returns></returns>
        public bool SaveProductImage(ProductImage productImage)
        {
            try
            {
                _db.ProductImage.Add(productImage);
                var resultQuery = _db.SaveChanges();
                if (resultQuery > 0)
                {
                    return true;
                }
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Delete an image of a product
        /// </summary>
        /// <param name="productImageId"></param>
        /// <param name="productCode"></param>
        /// <returns></returns>
        public bool DeleteProductImage(string productImageName, string productCode)
        {
            try
            {
                var selectProductImage = (from productImage in _db.ProductImage
                                          where productImage.Image == productImageName
                                                && productImage.ProductCode == productCode
                                          select productImage).FirstOrDefault();
                if (selectProductImage != null)
                {
                    _db.ProductImage.Remove(selectProductImage);
                    var resultQuery = _db.SaveChanges();
                    if (resultQuery > 0)
                    {
                        return true;
                    }
                    return false;
                }
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Create product location based on product code
        /// </summary>
        /// <param name="lstLocationId"></param>
        /// <param name="productCode"></param>
        /// <returns></returns>
        public bool SaveProductLocation(List<int> lstLocationId, string productCode)
        {
            try
            {
                List<ProductLocation> lstOldProductLocation = new List<ProductLocation>();
                lstOldProductLocation = this.GetListProductLocationByCode(productCode);
                Dictionary<int, bool> dicDetechProductLocation = new Dictionary<int, bool>();
                foreach (var item in lstOldProductLocation)
                {
                    dicDetechProductLocation.Add(item.Id, false);
                }

                // Loop in List sizeId, if don't have any record which has the same sizeId and productCode => create it, else update it
                foreach (var locationId in lstLocationId)
                {
                    var isExisted = _db.ProductLocation.Any(model => model.LocationId == locationId && model.ProductCode == productCode);
                    if (!isExisted)
                    {
                        ProductLocation productLocation = new ProductLocation();
                        productLocation.ProductCode = productCode;
                        productLocation.LocationId = locationId;
                        _db.ProductLocation.Add(productLocation);
                    }
                    else
                    {
                        var selectProductLocation = (from productLocation in _db.ProductLocation
                                                     where productLocation.LocationId == locationId && productLocation.ProductCode == productCode
                                                     select productLocation).FirstOrDefault();

                        // If is existed in Product Size and when update, this ProductSizeId still keep to use, set flag is true                
                        if (dicDetechProductLocation.ContainsKey(selectProductLocation.Id))
                        {
                            dicDetechProductLocation[selectProductLocation.Id] = true;
                        }
                    }
                }

                // Loop in Dictionary, if item has flag is false, that means this item don't keep to use, so delete it
                foreach (var item in dicDetechProductLocation)
                {
                    if (item.Value == false)
                    {
                        ProductLocation productLocationEnt = new ProductLocation();
                        productLocationEnt = this.GetProductLocationById(item.Key);

                        if (productLocationEnt != null)
                        {
                            _db.ProductLocation.Remove(productLocationEnt);
                        }
                        else
                        {
                            return false;
                        }
                    }
                }
                var resultQuery = _db.SaveChanges();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Delete Product Location when delete a product
        /// </summary>
        /// <param name="productCode"></param>
        /// <returns></returns>
        public bool DeleteProductLocation(string productCode)
        {
            List<ProductLocation> lstProductLocation = new List<ProductLocation>();
            lstProductLocation = this.GetListProductLocationByCode(productCode);
            foreach (var location in lstProductLocation)
            {
                location.IsDelete = true;
                _db.ProductLocation.Attach(location);
                _db.Entry(location).State = EntityState.Modified;
            }
            var resultQuery = _db.SaveChanges();
            if (resultQuery > 0)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Is existed Product Code in DB
        /// </summary>
        /// <param name="productCode"></param>
        /// <returns></returns>
        public bool IsExistedProductName(string productName, string productCode, bool isUpdateMode = false)
        {
            if (isUpdateMode)
            {
                return _db.Product.Any(model => model.ProductCode != productCode && model.ProductName == productName);
            }
            return _db.Product.Any(model => model.ProductName == productName);
        }

        /// <summary>
        /// Get string value of Gender, Female or male
        /// </summary>
        /// <param name="genderValue"></param>
        /// <returns></returns>
        private string GetGenderValue(int genderValue)
        {
            if (genderValue == CommonConst.MALE)
            {
                return CommonConst.STR_MALE_VALUE;
            }
            return CommonConst.STR_FEMALE_VALUE;
        }

        /// <summary>
        /// Count how many image of a ProductCode
        /// </summary>
        /// <param name="productCode"></param>
        /// <returns></returns>
        public int CountProductImageHas(string productCode)
        {
            var query = (from productImage in _db.ProductImage
                         where productImage.ProductCode == productCode
                         select productImage).Count();
            return query;
        }

        /// <summary>
        /// Detech a product is inputed the Size Quantity or not
        /// </summary>
        /// <param name="productCode"></param>
        /// <returns></returns>
        public bool IsInputedSizeQuantity(string productCode)
        {
            return _db.ProductSize.Any(model => model.ProductCode == productCode);
        }
    }
}